<template>
  <div>
    <el-card shadow="hover">
      <div style="display: flex">
        <el-select
          class="auto-width-el-select"
          @change="handleTableChange"
          :value="currentTable?.name ?? '--'"
          size="medium">
          <template slot="prefix">
            {{ tables.find(table => table.name === (currentTable?.name ?? '--'))?.name ?? '--' }}
          </template>
          <el-option
            v-for="table in tables"
            :key="table.name"
            :value="table.name"
            :label="table.name">
          </el-option>
        </el-select>
        <div style="width: 10px"></div>
        <el-tooltip placement="top">
          <div slot="content">复制表名</div>
          <el-button
            size="medium"
            @click="handleCopy(currentTable?.name ?? '--')"
            class="el-icon-document-copy">
          </el-button>
        </el-tooltip>
      </div>
      <div style="height: 10px"></div>
      <el-descriptions :column="2">
        <el-descriptions-item label="列族">
          {{ currentTable?.families?.join('   ') ?? '--' }}
        </el-descriptions-item>
      </el-descriptions>
    </el-card>
    <div style="height: 20px;"></div>
    <el-card shadow="hover">
      <div style="display: flex">
        <el-button
          @click="handleDelete"
          v-if="multipleSelection.length>0"
          size="medium"
          type="danger"
          icon="el-icon-delete">
          删除数据
        </el-button>
        <el-button
          @click="handleCreate"
          size="medium"
          type="primary"
          icon="el-icon-plus">
          新增数据
        </el-button>
        <el-button
          @click="drawerVisible = true"
          size="medium"
          icon="el-icon-setting">
          解析方式
        </el-button>
        <div style="flex: 1"></div>
        <el-button
          @click="loadAllRecord"
          :loading="isLoading"
          size="medium"
          icon="el-icon-refresh">
          刷新数据
        </el-button>
      </div>
      <div style="height: 10px"></div>
      <el-table
        v-loading="isLoading"
        :data="tableData"
        border
        style="width: 100%"
        @selection-change="handleSelectionChange">
        <el-table-column
          :align="'center'"
          type="selection"
          width="50">
        </el-table-column>
        <el-table-column
          :align="'center'"
          label="行键">
          <template v-slot="scope">
              <span v-if="scope.row['rowKey']?.dataType === 'hex'">
                <span
                  v-for="(hex,hexIndex) in scope.row['rowKey'].hexValue"
                  class="byte-style"
                  :key="hexIndex">{{ hex }}</span>
              </span>
            <div v-else style="text-align: center">{{ scope.row['rowKey']?.text }}</div>
          </template>
        </el-table-column>
        <el-table-column
          v-for="(config,index) in columnConfig"
          :key="index"
          :align="'center'"
          :label="config.family">
          <el-table-column
            v-for="qualifier in config.qualifiers"
            :key="`${config.family}:${qualifier}`"
            :align="'center'"
            :label="qualifier">
            <template v-slot="scope">
              <span v-if="scope.row[`${config.family}:${qualifier}`]?.dataType === 'hex'">
                <span
                  v-for="(hex,hexIndex) in scope.row[`${config.family}:${qualifier}`].hexValue"
                  class="byte-style"
                  :key="hexIndex">{{ hex }}</span>
              </span>
              <div v-else style="text-align: center">{{ scope.row[`${config.family}:${qualifier}`]?.text }}</div>
            </template>
          </el-table-column>
        </el-table-column>
        <el-table-column
          fixed="right"
          :align="'center'"
          label="操作"
          width="100">
          <template v-slot="scope">
            <el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>
          </template>
        </el-table-column>
        <el-empty slot="empty" description="暂无数据"></el-empty>
      </el-table>
    </el-card>
    <el-dialog :title="dialogMode==='view'?'查看数据':'新增数据'" :visible.sync="dialogVisible" :append-to-body="true">
      <el-form :model="newRecord">
        <el-form-item label="行键" label-width="80px">
          <div style="display: flex;justify-content: left;align-items:baseline">
            <el-input
              :readonly="dialogMode==='view'"
              v-model="newRecord.rowKey"
              placeholder="数据"
              size="medium"
              style="flex: 1">
            </el-input>
            <div style="width: 15px"></div>
            <el-tooltip placement="top">
              <div slot="content">{{ dialogMode === 'view' ? '行键的解析方式' : '选择行键的存储类型' }}</div>
              <el-select
                :disabled="dialogMode==='view'"
                v-model="newRecord.rowKeyType"
                placeholder="数据类型"
                size="medium"
                style="width: 120px;">
                <el-option-group
                  v-for="group in dataTypes"
                  :key="group.name"
                  :label="group.name">
                  <el-option
                    v-for="item in group.value"
                    :key="item"
                    :label="item"
                    :value="item">
                  </el-option>
                </el-option-group>
              </el-select>
            </el-tooltip>
          </div>
        </el-form-item>
        <el-form-item
          v-for="(column,i) in newRecord.columns"
          :label="`列值${i+1}`"
          :key="column.key"
          label-width="80px">
          <div style="display: flex;justify-content: space-between;align-items:baseline">
            <el-tooltip placement="top">
              <div slot="content">{{ dialogMode === 'view' ? '列族' : '选择列族' }}</div>
              <el-select
                :disabled="dialogMode==='view'"
                v-model="column.family"
                placeholder="列族"
                size="medium"
                style="width: 120px;">
                <el-option
                  v-for="family in currentTable.families"
                  :key="family"
                  :label="family"
                  :value="family">
                </el-option>
              </el-select>
            </el-tooltip>
            <el-tooltip placement="top">
              <div slot="content">{{ dialogMode === 'view' ? '列限定符' : '填写列限定符' }}</div>
              <el-input
                :readonly="dialogMode==='view'"
                v-model="column.qualifier"
                placeholder="列限定符"
                size="medium"
                style="width: 120px;">
              </el-input>
            </el-tooltip>
            <el-input
              :readonly="dialogMode==='view'"
              v-model="column.value"
              placeholder="数据"
              size="medium"
              style="width: 120px;">
            </el-input>
            <el-tooltip placement="top">
              <div slot="content">{{ dialogMode === 'view' ? '解析方式' : '选择存储类型' }}</div>
              <el-select
                :disabled="dialogMode==='view'"
                v-model="column.dataType"
                placeholder="数据类型"
                size="medium"
                style="width: 120px;">
                <el-option-group
                  v-for="group in dataTypes"
                  :key="group.name"
                  :label="group.name">
                  <el-option
                    v-for="item in group.value"
                    :key="item"
                    :label="item"
                    :value="item">
                  </el-option>
                </el-option-group>
              </el-select>
            </el-tooltip>
            <el-button
              v-if="dialogMode!=='view'"
              @click="newRecord.columns.splice(i,1)"
              type="danger"
              size="medium"
              icon="el-icon-delete">
            </el-button>
          </div>
        </el-form-item>
        <el-form-item
          v-if="dialogMode!=='view'"
          label=""
          label-width="80px">
          <el-button
            @click="addRecordInput"
            size="medium"
            icon="el-icon-plus"
            style="border-style: dashed;width: 100%">
            列值
          </el-button>
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="handleCancelCreate" size="small">取 消</el-button>
        <el-button type="primary" @click="handleConfirmCreate" size="small">确 定</el-button>
      </div>
    </el-dialog>
    <el-drawer
      title="解析方式"
      :visible.sync="drawerVisible"
      direction="rtl">
      <div style="margin: 20px" class="custom-tree-node">
        <span style="color: black">行键</span>
        <span>
        <el-select
          :value="columnTypeMap['rowKey'] ?? 'hex'"
          @change="handleRowKeyDataTypeSelectChange"
          size="mini"
          placeholder="数据类型">
              <el-option-group
                v-for="group in dataTypes"
                :key="group.name"
                :label="group.name">
                <el-option
                  v-for="item in group.value"
                  :key="item"
                  :label="item"
                  :value="item">
                </el-option>
              </el-option-group>
            </el-select>
        </span>
      </div>
      <el-tree
        style="margin: 20px"
        :data="columnConfigTree"
        node-key="id"
        default-expand-all
        :expand-on-click-node="true">
        <template v-slot="{node}">
          <div class="custom-tree-node">
            <span>{{ node.label }}</span>
            <span>
        <el-select
          :value="columnTypeMap[node.data.id]"
          @change="handleDataTypeSelectChange($event, node)"
          size="mini"
          placeholder="数据类型">
              <el-option-group
                v-for="group in dataTypes"
                :key="group.name"
                :label="group.name">
                <el-option
                  v-for="item in group.value"
                  :key="item"
                  :label="item"
                  :value="item">
                </el-option>
              </el-option-group>
            </el-select>
        </span>
          </div>
        </template>
      </el-tree>
    </el-drawer>
  </div>
</template>
<script>
import {mapActions, mapGetters} from 'vuex'

export default {
  data() {
    return {
      isLoading: false,
      multipleSelection: [],
      dialogVisible: false,
      dialogMode: 'create',
      drawerVisible: false,
      dataTypes: [
        {
          name: '字节流',
          value: ['hex']
        },
        {
          name: '字符串',
          value: ['string']
        },
        {
          name: '整数',
          value: ['short', 'integer', 'long']
        },
        {
          name: '浮点数',
          value: ['float', 'double']
        },
        {
          name: '布尔值',
          value: ['boolean']
        }
      ],
      records: [],
      newRecord: {
        rowKey: '',
        rowKeyType: 'string',
        columns: []
      },
      select: 'hex'
    }
  },
  computed: {
    columnConfig() {
      const columnMap = {}
      for (const record of this.records) {
        const col2val = record['col2val']
        if (col2val) {
          const cols = Object.keys(col2val)
          for (const col of cols) {
            const [family, qualifier] = col.split(':')
            if (columnMap[family]) {
              columnMap[family].push(qualifier)
            } else {
              columnMap[family] = [qualifier]
            }
          }
        }
      }
      const data = []
      for (const family of Object.keys(columnMap)) {
        data.push({
          family,
          qualifiers: [...new Set(columnMap[family])]
        })
      }
      return data
    },
    columnConfigTree() {
      const data = []
      for (const config of this.columnConfig) {
        const treeNode = {
          id: config.family,
          label: config.family,
          children: []
        }
        for (const qualifier of config.qualifiers) {
          treeNode.children.push({
            id: `${config.family}:${qualifier}`,
            label: qualifier
          })
        }
        data.push(treeNode)
      }
      return data
    },
    tableData() {
      const data = []
      for (const record of this.records) {
        const col2val = record['col2val']
        const row = {}
        if (col2val) {
          const cols = ['rowKey', ...Object.keys(col2val)]
          for (const col of cols) {
            const value = col === 'rowKey' ? record['rowKey'] : col2val[col]
            const hexText = this.convert(value, 'hex')
            const hexValue = []
            for (let i = 0; i < hexText.length; i = i + 2) {
              hexValue.push(hexText.slice(i, i + 2))
            }
            const dataType = this.columnTypeMap[col] ?? 'hex'
            // 对于前端处理不了的转换, 使用后端提供的结果
            const hintValue = record?.hint?.[`${col}:${dataType}`] ?? '[ERROR]'
            const text = this.convert(value, dataType, hintValue)
            if (col === 'rowKey') {
              row['rowKey'] = {
                value,
                hexValue,
                dataType,
                text
              }
            } else {
              const [family, qualifier] = col.split(':')
              row[`${family}:${qualifier}`] = {
                family,
                qualifier,
                value,
                hexValue,
                dataType,
                text
              }
            }
          }
        }
        data.push(row)
      }
      return data
    },
    ...mapGetters({
      tables: 'global/getTables',
      currentTable: 'global/getCurrentTable',
      columnTypeMap: 'profile/getColumnTypeMap'
    })
  },
  methods: {
    async init() {
      if (!this.currentTable) {
        const resp = await this.$api.table.listTable()
        if (resp?.ok) {
          const tables = resp.data
          this.setTables(tables)
          if (tables.length === 0) {
            this.$message.info('还没有在数据库中创建表')
          } else {
            this.setCurrentTable(tables[0])
          }
        } else {
          this.$message.error('表数据查询失败')
        }
      }
      await this.loadAllRecord()
    },
    handleTableChange(tableName) {
      const table = this.tables.find(table => table.name === tableName)
      this.setCurrentTable(table)
      this.loadAllRecord()
    },
    async loadAllRecord() {
      if (!this.currentTable) {
        return
      }
      this.isLoading = true
      const resp = await this.$api.record.listRecord(this.currentTable.name, '')
      if (resp?.ok) {
        this.records = resp.data
      } else {
        this.$message.error('数据获取失败')
      }
      this.isLoading = false
    },
    handleClick(row) {
      this.dialogMode = 'view'
      this.newRecord.rowKey = row?.rowKey.text ?? ''
      this.newRecord.rowKeyType = row?.rowKey.dataType
      this.newRecord.columns = Object.keys(row)
        .filter(k => k !== 'rowKey')
        .map(k => ({
          key: Date.now(),
          family: row[k]['family'],
          qualifier: row[k]['qualifier'],
          dataType: row[k]['dataType'],
          value: row[k]['text']
        }))
      this.dialogVisible = true
    },
    handleSelectionChange(val) {
      this.multipleSelection = val
    },
    handleCreate() {
      this.dialogMode = 'create'
      this.newRecord.rowKey = ''
      this.newRecord.rowKeyType = this.columnTypeMap['rowKey'] ?? 'hex'
      this.newRecord.columns = []
      this.dialogVisible = true
    },
    handleCancelCreate() {
      this.dialogVisible = false
    },
    async handleConfirmCreate() {
      if (this.dialogMode === 'view') {
        this.dialogVisible = false
        return
      }
      const {rowKey, rowKeyType, columns} = this.newRecord
      const col2val = {}
      for (const column of columns) {
        this.setColumnType({
          key: `${column.family}:${column.qualifier}`,
          value: column.dataType
        })
        col2val[`${column.family}:${column.qualifier}:${column.dataType}`] = column.value
      }
      const resp = await this.$api.record.createRecord(this.currentTable.name, [{rowKey, rowKeyType, col2val}])
      if (resp?.ok) {
        this.$message.success('新增成功')
        this.dialogVisible = false
        this.newRecord.rowKey = ''
        this.newRecord.rowKeyType = this.columnTypeMap['rowKey']
        this.newRecord.columns = []
        await this.loadAllRecord()
      } else {
        this.$message.error(resp?.msg ?? '新增失败')
      }
    },
    async handleDelete() {
      const rowKeyTexts = this.multipleSelection.map(record => record.rowKey.text)
      try {
        const action = await this.$confirm(`此操作将永久删除 key=${rowKeyTexts} 的行 , 是否继续?`, '提示', {
          confirmButtonText: '确 定',
          cancelButtonText: '取 消',
          type: 'warning'
        })
        if (action === 'confirm') {
          const rowKeys = this.multipleSelection.map(record => record.rowKey.value)
          const resp = await this.$api.record.deleteRecord(this.currentTable.name, rowKeys)
          if (resp?.ok) {
            this.$message.success('删除成功')
            await this.loadAllRecord()
          } else {
            this.$message.error(resp?.msg ?? '删除失败')
          }
        }
      } catch (e) {
        console.log(`取消删除 key=${rowKeyTexts} 的行`)
      }
    },
    addRecordInput() {
      this.newRecord.columns.push({
        key: Date.now(),
        family: this.currentTable?.families?.[0] ?? '',
        qualifier: '',
        dataType: 'string',
        value: ''
      })
    },
    convert(bytes, type, hintValue) {
      if (type === 'string') {
        return hintValue
      } else if (type === 'hex') {
        return this.$util.bytesToHex(bytes)
      } else if (type === 'integer') {
        return hintValue
      } else if (type === 'short') {
        return hintValue
      } else if (type === 'long') {
        return hintValue
      } else if (type === 'boolean') {
        return hintValue
      } else if (type === 'double') {
        return hintValue
      } else if (type === 'float') {
        return hintValue
      } else {
        throw new Error(`数据 ${bytes} 无法转化为类型 ${type}`)
      }
    },
    handleDataTypeSelectChange(value, node) {
      if (node.isLeaf) {
        const key = node.data.id
        this.setColumnType({key, value})
      } else {
        for (const childNode of node.childNodes) {
          const key = childNode.data.id
          this.setColumnType({key, value})
        }
      }
    },
    handleRowKeyDataTypeSelectChange(value) {
      this.setColumnType({
        key: 'rowKey',
        value: value
      })
    },
    handleCopy(text) {
      const textNode = document.createElement('textarea')
      textNode.setAttribute('readonly', 'readonly')
      textNode.value = text
      document.body.appendChild(textNode)
      textNode.setSelectionRange(0, textNode.value.length)
      textNode.select()
      document.execCommand('copy')
      if (document.body.removeChild(textNode)) {
        this.$message({type: 'success', message: `已复制 ${text}`})
      } else {
        this.$message({type: 'error', message: '复制失败'})
      }
    },
    ...mapActions({
      setTables: 'global/setTables',
      setCurrentTable: 'global/setCurrentTable',
      setColumnType: 'profile/setColumnType'
    })
  },
  async mounted() {
    await this.init()
  }
}
</script>
<style lang="scss" scoped>
.auto-width-el-select {
  min-width: 200px;

  ::v-deep {

    .el-input__prefix {
      user-select: none;
      position: relative;
      left: 0;
      color: #ffffff00;
      font-size: 16px;
      box-sizing: border-box;
      border: 1px solid #ffffff00;
      padding: 0 30px;
      height: 36px;
      line-height: 36px;
    }

    input {
      position: absolute;
    }
  }
}

::v-deep {
  .el-table {
    &::before {
      //去除底部白线
      left: 0;
      bottom: 0;
      width: 100%;
      height: 0;
    }

    th {
      &.el-table__cell {
        background-color: #f8f8f8;
      }
    }

    thead {
      &.is-group {
        th {
          &.el-table__cell {
            background-color: #f8f8f8;
          }
        }
      }
    }
  }

  .el-table__body-wrapper {
    .el-table__row {
      .cell {
        text-align: left;
      }
    }
  }

  .el-drawer__header {
    color: black;
    font-weight: bold;
  }

  .el-tree-node__content {
    height: 36px;
  }
}

.byte-style {
  margin-left: 1px;
  margin-right: 1px;
  padding: 1px;
  background-color: #314161;
  color: white;
  white-space: nowrap;
}

.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}
</style>